<template>
	<div>
		<div
			class="fixed top-0 left-0 right-0 bg-gray-800 text-white p-2 flex justify-start"
		>
			<button
				@click="toggleView"
				class="px-4 py-2 rounded-md hover:bg-gray-700"
			>
				切换视角
			</button>
			<!--      <select v-model="selectedDepartment" @change="filterCubes" class="ml-2 px-2 py-1 rounded-md">-->
			<!--        <option value="">全部科室</option>-->
			<!--        <option v-for="(dept, index) in uniqueDepartments" :key="index" :value="dept">{{dept}}</option>-->
			<!--      </select>-->
		</div>
		<div ref="container" class="h-screen w-screen"></div>
	</div>
</template>

<script>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { CatmullRomCurve3 } from 'three';
import cubesData from './cubes.json';
import { Draw } from 'ol/interaction';

export default {
  name: 'IndoorMap',
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      floor: null,
      cubes: [],
      selectedCube: null,
      walls: [],
      cubeData: [],
      isTopView: false,
      selectedDepartment: '',
      navigationLine: null
    };
  },
  computed: {
    deptData() {
      return cubesData;
    },
    uniqueDepartments() {
      return Array.from(new Set(this.cubeData.map(data => data.text)));
    }
  },
  async mounted() {
    // 动态引入 TWEEN.js
    if (document.head) {
      const script = document.createElement('script');
      script.src = 'https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js';
      script.onload = () => {
        this.initScene();
        this.createFloor();
        this.createWalls();
        this.fetchCubeData();
        this.createCubes();
        this.addLight();
        this.addEventListeners();
        // 假设绘制内科到外科的导航线
        this.drawNavigationLineByPoints('内科', '外科');
        this.drawNavigationLineByPoints('外科', '心电');
        this.drawNavigationLineByPoints('心电', '耳鼻喉');
        this.drawNavigationLineByPoints('耳鼻喉', '采血室');
        this.drawNavigationLineByPoints('采血室', 'C13');
        this.animate();
      };
      document.head.appendChild(script);
    }
  },
  methods: {
    // 初始化场景、相机、渲染器和控制器
    initScene() {
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0x808080);
      this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
      // 调整相机位置
      this.camera.position.z = 60;
      this.camera.position.y = 35;
      // 开启抗锯齿
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      if (this.$refs.container) {
        this.$refs.container.appendChild(this.renderer.domElement);
      }
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.minPolarAngle = 0;
      this.controls.maxPolarAngle = Math.PI / 2;
      const originalLeft = this.controls.mouseButtons.LEFT;
      this.controls.mouseButtons.LEFT = this.controls.mouseButtons.RIGHT;
      this.controls.mouseButtons.RIGHT = originalLeft;
      this.controls.screenSpacePanning = false;
    },
    // 创建地板
    createFloor() {
      const geometry = new THREE.PlaneGeometry(120, 80);
      const material = new THREE.MeshBasicMaterial({ color: 0xf5f5f5, side: THREE.DoubleSide });
      this.floor = new THREE.Mesh(geometry, material);
      this.floor.rotation.x = -Math.PI / 2;
      this.scene.add(this.floor);
    },
    // 创建地板周围的墙体
    createWalls() {
      const wallHeight = 2;
      const wallThickness = 0.5;
      const floorWidth = 120;
      const floorHeight = 80;
      const offset = 2;

      const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });

      // 前墙
      const frontWallGeometry = new THREE.BoxGeometry(floorWidth - 2 * offset, wallHeight, wallThickness);
      const frontWall = new THREE.Mesh(frontWallGeometry, wallMaterial);
      frontWall.position.set(0, wallHeight / 2, floorHeight / 2 - offset + wallThickness / 2);
      this.scene.add(frontWall);
      this.walls.push(frontWall);

      // 后墙
      const backWallGeometry = new THREE.BoxGeometry(floorWidth - 2 * offset, wallHeight, wallThickness);
      const backWall = new THREE.Mesh(backWallGeometry, wallMaterial);
      backWall.position.set(0, wallHeight / 2, -floorHeight / 2 + offset - wallThickness / 2);
      this.scene.add(backWall);
      this.walls.push(backWall);

      // 左墙
      const leftWallGeometry = new THREE.BoxGeometry(wallThickness, wallHeight, floorHeight - 2 * offset);
      const leftWall = new THREE.Mesh(leftWallGeometry, wallMaterial);
      leftWall.position.set(-floorWidth / 2 + offset - wallThickness / 2, wallHeight / 2, 0);
      this.scene.add(leftWall);
      this.walls.push(leftWall);

      // 右墙
      const rightWallGeometry = new THREE.BoxGeometry(wallThickness, wallHeight, floorHeight - 2 * offset);
      const rightWall = new THREE.Mesh(rightWallGeometry, wallMaterial);
      rightWall.position.set(floorWidth / 2 - offset + wallThickness / 2, wallHeight / 2, 0);
      this.scene.add(rightWall);
      this.walls.push(rightWall);
    },
    // 从 JSON 文件获取立方体数据
    async fetchCubeData() {
      try {
        this.cubeData = this.deptData;
      } catch (error) {
        console.error('获取立方体数据时出错:', error);
      }
    },
    // 创建长方体
    createCubes() {
      for (const data of this.cubeData) {
        const { sizeX, sizeZ, x, z, color, text, textColor } = data;
        const cubeHeight = 1.5;

        // 自定义着色器材质实现自上而下颜色加深
        const vertexShader = `
          varying vec3 vPosition;
          void main() {
            vPosition = position;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
          }
        `;
        const fragmentShader = `
          uniform vec3 topColor;
          uniform vec3 bottomColor;
          uniform float height;
          varying vec3 vPosition;
          void main() {
            float t = (vPosition.y + height / 2.0) / height;
            vec3 color = mix(bottomColor, topColor, t);
            gl_FragColor = vec4(color, 0.8);
          }
        `;
        const topColor = new THREE.Color(color);
        const bottomColor = new THREE.Color(color).multiplyScalar(0.6);
        const material = new THREE.ShaderMaterial({
          uniforms: {
            topColor: { value: topColor },
            bottomColor: { value: bottomColor },
            height: { value: cubeHeight }
          },
          vertexShader: vertexShader,
          fragmentShader: fragmentShader,
          transparent: true
        });

        const geometry = new THREE.BoxGeometry(sizeX, cubeHeight, sizeZ);
        const cube = new THREE.Mesh(geometry, material);
        cube.position.x = x;
        cube.position.y = cubeHeight / 2;
        cube.position.z = z;

        const edges = new THREE.EdgesGeometry(geometry);
        const edgeColor = new THREE.Color(0xFFFFFF);
        const edgeMaterial = new THREE.LineBasicMaterial({ color: edgeColor.getHex() });
        const edgeLines = new THREE.LineSegments(edges, edgeMaterial);
        cube.add(edgeLines);

        const scaleFactor = 4;
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        context.font = `20px Arial`;
        const metrics = context.measureText(text);
        const textWidth = metrics.width;
        canvas.width = textWidth * scaleFactor;
        canvas.height = 40 * scaleFactor;
        context.font = `20px Arial`;
        context.fillStyle = textColor;
        context.scale(scaleFactor, scaleFactor);
        context.fillText(text, 0, 24);

        const texture = new THREE.CanvasTexture(canvas);
        texture.minFilter = THREE.LinearFilter;
        texture.magFilter = THREE.LinearFilter;
        const textMaterial = new THREE.MeshBasicMaterial({ map: texture, transparent: true });
        const shrinkFactor = 0.6;
        const textGeometry = new THREE.PlaneGeometry(sizeX * 0.8 * shrinkFactor, sizeZ * 0.8 * shrinkFactor);
        const textMesh = new THREE.Mesh(textGeometry, textMaterial);
        textMesh.position.set(0, cubeHeight / 2 + 0.01, 0);
        textMesh.rotation.x = -Math.PI / 2;
        cube.add(textMesh);

        this.scene.add(cube);
        this.cubes.push(cube);
      }
    },
    // 添加光源
    addLight() {
      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(0, 0, 50);
      this.scene.add(light);
    },
    // 添加事件监听器
    addEventListeners() {
      window.addEventListener('click', this.onMouseClick, false);
      window.addEventListener('resize', this.onWindowResize, false);
    },
    // 处理鼠标点击事件
    onMouseClick(event) {
      const raycaster = new THREE.Raycaster();
      const mouse = new THREE.Vector2();
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
      raycaster.setFromCamera(mouse, this.camera);
      const intersects = raycaster.intersectObjects(this.cubes, false);
      if (intersects.length > 0) {
        if (this.selectedCube) {
          const originalData = this.cubeData.find(data => {
            const cube = this.cubes.find(c => c === this.selectedCube);
            return cube.position.x === data.x && cube.position.z === data.z;
          });
          const originalTopColor = new THREE.Color(originalData.color);
          const originalBottomColor = new THREE.Color(originalData.color).multiplyScalar(0.6);

          new window.TWEEN.Tween(this.selectedCube.material.uniforms.topColor.value)
              .to({ r: originalTopColor.r, g: originalTopColor.g, b: originalTopColor.b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();
          new window.TWEEN.Tween(this.selectedCube.material.uniforms.bottomColor.value)
              .to({ r: originalBottomColor.r, g: originalBottomColor.g, b: originalBottomColor.b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();

          new window.TWEEN.Tween(this.selectedCube.children[0].material.color)
              .to({ r: new THREE.Color(originalData.color).multiplyScalar(0.8).r, g: new THREE.Color(originalData.color).multiplyScalar(0.8).g, b: new THREE.Color(originalData.color).multiplyScalar(0.8).b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();
        }
        this.selectedCube = intersects[0].object;
        // const selectedData = this.cubeData.find(data => {
        //   return this.selectedCube.position.x === data.x && this.selectedCube.position.z === data.z;
        // });
        const targetTopColor = new THREE.Color(0xFE7949);
        const targetBottomColor = new THREE.Color(0xFE7949).multiplyScalar(0.6);

        new window.TWEEN.Tween(this.selectedCube.material.uniforms.topColor.value)
            .to({ r: targetTopColor.r, g: targetTopColor.g, b: targetTopColor.b }, 500)
            .easing(window.TWEEN.Easing.Quadratic.InOut)
            .start();
        new window.TWEEN.Tween(this.selectedCube.material.uniforms.bottomColor.value)
            .to({ r: targetBottomColor.r, g: targetBottomColor.g, b: targetBottomColor.b }, 500)
            .easing(window.TWEEN.Easing.Quadratic.InOut)
            .start();

        new window.TWEEN.Tween(this.selectedCube.children[0].material.color)
            .to({ r: 1, g: 1, b: 1 }, 500)
            .easing(window.TWEEN.Easing.Quadratic.InOut)
            .start();
      } else {
        if (this.selectedCube) {
          const originalData = this.cubeData.find(data => {
            const cube = this.cubes.find(c => c === this.selectedCube);
            return cube.position.x === data.x && cube.position.z === data.z;
          });
          const originalTopColor = new THREE.Color(originalData.color);
          const originalBottomColor = new THREE.Color(originalData.color).multiplyScalar(0.6);

          new window.TWEEN.Tween(this.selectedCube.material.uniforms.topColor.value)
              .to({ r: originalTopColor.r, g: originalTopColor.g, b: originalTopColor.b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();
          new window.TWEEN.Tween(this.selectedCube.material.uniforms.bottomColor.value)
              .to({ r: originalBottomColor.r, g: originalBottomColor.g, b: originalBottomColor.b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();

          new window.TWEEN.Tween(this.selectedCube.children[0].material.color)
              .to({ r: new THREE.Color(originalData.color).multiplyScalar(0.8).r, g: new THREE.Color(originalData.color).multiplyScalar(0.8).g, b: new THREE.Color(originalData.color).multiplyScalar(0.8).b }, 500)
              .easing(window.TWEEN.Easing.Quadratic.InOut)
              .start();

          this.selectedCube = null;
        }
      }
    },
    // 处理窗口大小改变事件
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    },
    // 动画循环，用于持续渲染场景
    animate() {
      requestAnimationFrame(this.animate);
      if (window.TWEEN) {
        window.TWEEN.update();
      }
      this.controls.update();
      this.renderer.render(this.scene, this.camera);
    },
    // 切换视角
    toggleView() {
      this.isTopView = !this.isTopView;
      const targetPosition = this.isTopView ? { x: 0, y: 100, z: 0 } : { x: 0, y: 35, z: 60 };
      new THREE.Vector3(0, 0, 0);
      if (window.TWEEN) {
        new window.TWEEN.Tween(this.camera.position)
            .to(targetPosition, 1000)
            .easing(window.TWEEN.Easing.Quadratic.InOut)
            .start();

        new window.TWEEN.Tween(this.camera.rotation)
            .to({
              x: this.isTopView ? -Math.PI / 2 : 0,
              y: 0,
              z: 0
            }, 1000)
            .easing(window.TWEEN.Easing.Quadratic.InOut)
            .start();
      }
    },
    // 过滤科室
    filterCubes() {
      this.cubes.forEach(cube => {
        const cubeData = this.cubeData.find(data => {
          return cube.position.x === data.x && cube.position.z === data.z;
        });
        if (this.selectedDepartment === '' || cubeData.text === this.selectedDepartment) {
          cube.visible = true;
        } else {
          cube.visible = false;
        }
      });
    },
    // 根据科室名称查找对应的立方体
    findCubeByDepartment(department) {
      return this.cubes.find(cube => {
        const cubeData = this.cubeData.find(data => {
          return cube.position.x === data.x && cube.position.z === data.z;
        });
        return cubeData && cubeData.text === department;
      });
    },
    // 根据起点和终点科室名称绘制导航线（带障碍物规避）
    drawNavigationLineByPoints(startDepartment, endDepartment) {
      // 查找起点和终点对应的立方体
      const startCube = this.findCubeByDepartment(startDepartment);
      const endCube = this.findCubeByDepartment(endDepartment);

      if (startCube && endCube) {
        // 获取起点和终点的尺寸数据
        const startData = this.cubeData.find(data =>
          startCube.position.x === data.x && startCube.position.z === data.z
        );
        const endData = this.cubeData.find(data =>
          endCube.position.x === data.x && endCube.position.z === data.z
        );

        // 计算起点到终点的方向差
        const dx = endCube.position.x - startCube.position.x;
        const dz = endCube.position.z - startCube.position.z;

        // 计算起点中心位置（考虑不同方向）
        let startCenter = this.calculateStartCenter(startCube, startData, dx, dz);
        // 计算终点中心位置（考虑不同方向）
        let endCenter = this.calculateEndCenter(endCube, endData, dx, dz);

        // 获取所有障碍物信息（立方体+墙体）
        const obstacles = this.getObstacles(startCube, endCube);

        // 使用A*算法寻找最优路径
        const pathPoints = this.aStarPathfinding(
          startCenter,
          endCenter,
          obstacles,
          2.0 // 网格精度
        );

        // 创建CatmullRom曲线路径
        const curve = new CatmullRomCurve3(pathPoints);
        const curvePoints = curve.getPoints(50);

        // 创建导航线几何体和材质
        const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
        const material = new THREE.LineBasicMaterial({
          color: new THREE.Color('#6D9f61'),
          linewidth: 5,
          antialias: true
        });

        // 如果已存在导航线则先移除
        if (this.navigationLine) {
          this.scene.remove(this.navigationLine);
        }

        // 创建新导航线并加入场景
        this.navigationLine = new THREE.Line(geometry, material);
        this.scene.add(this.navigationLine);

        // 创建路径箭头指示
        this.createPathArrows(curvePoints);

        console.log('带障碍规避的导航线已生成');
      } else {
        console.error(`路径规划失败：未找到 ${startDepartment} 或 ${endDepartment}`);
      }
    },

    // ... existing code ...

    // 新增方法：A*路径规划算法
    aStarPathfinding(start, end, obstacles, gridSize) {
      // 实现步骤：
      // 1. 将场景网格化
      // 2. 标记障碍网格
      // 3. 使用优先队列进行路径搜索
      // 4. 回溯生成路径点
      // （具体实现代码需补充）
    },

    // 新增方法：获取所有障碍物信息
    getObstacles(currentStart, currentEnd) {
      return [
        ...this.cubes.filter(cube => cube !== currentStart && cube !== currentEnd),
        ...this.walls
      ].map(obj => ({
        position: obj.position,
        size: this.getObjectSize(obj)
      }));
    },

    // 新增方法：创建路径箭头
    createPathArrows(points) {
      const arrowSpacing = 10;
      for (let i = arrowSpacing; i < points.length - 1; i += arrowSpacing) {
        // 计算箭头方向
        const direction = new THREE.Vector3()
          .subVectors(points[i + 1], points[i])
          .normalize();

        // 创建箭头模型
        const arrow = this.createArrowMesh(direction, points[i]);
        this.scene.add(arrow);
      }
    }
  }
};
</script>

<style scoped>
/* 样式 */
</style>
